﻿using System;
using System.Windows;
using DotNetImage.Types;

namespace DotNetImage.Imaging.Filters
{
    public class OffsetFilterAntiAlias : FilterBase
    {
        public FloatPoint[,] Offset { get; set; }

        protected override void PrepareData(DotNetImage bmp)
        {
            bmp.CreatePixelCopy();
        }

        protected override void ProcessPixel(ref Pixel pix, uint x, uint y)
        {
            double xOffset = Offset[x, y].X;
            double yOffset = Offset[x, y].Y;

            // Setup
            uint floor_x = (uint)Math.Floor(xOffset);
            uint floor_y = (uint)Math.Floor(yOffset);
            uint ceil_x = floor_x + 1;
            uint ceil_y = floor_y + 1;

            if (floor_y >= 0 && ceil_y < nHeight && floor_x >= 0 && ceil_x < nWidth)
            {
                byte p1;
                byte p2;

                double fraction_x = xOffset - floor_x;
                double fraction_y = yOffset - floor_y;
                double one_minus_x = 1.0 - fraction_x;
                double one_minus_y = 1.0 - fraction_y;

                Pixel pix1 = Subject.GetPreservedPixel(floor_x, floor_y);
                Pixel pix2 = Subject.GetPreservedPixel(ceil_x, floor_y);
                Pixel pix3 = Subject.GetPreservedPixel(floor_x, ceil_y);
                Pixel pix4 = Subject.GetPreservedPixel(ceil_x, ceil_y);

                // Blue
                p1 = (byte)(one_minus_x * (double)(pix1.Blue) + fraction_x * (double)(pix2.Blue));
                p2 = (Byte)(one_minus_x * (double)(pix3.Blue) + fraction_x * (double)(pix4.Blue));
                pix.Blue = (Byte)(one_minus_y * (double)(p1) + fraction_y * (double)(p2)); ;

                // Green
                p1 = (byte)(one_minus_x * (double)(pix1.Green) + fraction_x * (double)(pix2.Green));
                p2 = (Byte)(one_minus_x * (double)(pix3.Green) + fraction_x * (double)(pix4.Green));
                pix.Green = (Byte)(one_minus_y * (double)(p1) + fraction_y * (double)(p2)); ;

                // Red
                p1 = (byte)(one_minus_x * (double)(pix1.Red) + fraction_x * (double)(pix2.Red));
                p2 = (Byte)(one_minus_x * (double)(pix3.Red) + fraction_x * (double)(pix4.Red));
                pix.Red = (Byte)(one_minus_y * (double)(p1) + fraction_y * (double)(p2)); ;
            }
        }
    }
}
